﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace CSharpExperiments.Collections
{
	// Stolen from:
	// https://github.com/jsonmez/Defaultable-Dictionary/blob/master/DefaultableDictionary/DefaultableDictionary/DefaultableDictionary.cs

	public class DefaultableDictionary<K, V> : IDictionary<K, V>
	{
        private readonly IDictionary<K, V> dictionary;
        private readonly Func<K, V> valueFactory;

        public DefaultableDictionary(IDictionary<K, V> dictionary, Func<K, V> valueFactory)
        {
            this.dictionary = dictionary;
            this.valueFactory = valueFactory;
        }

        public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
        {
            return dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(KeyValuePair<K, V> item)
        {
            dictionary.Add(item);
        }

        public void Clear()
        {
            dictionary.Clear();
        }

        public bool Contains(KeyValuePair<K, V> item)
        {
            return dictionary.Contains(item);
        }

        public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
        {
            dictionary.CopyTo(array, arrayIndex);
        }

        public bool Remove(KeyValuePair<K, V> item)
        {
            return dictionary.Remove(item);
        }

        public int Count
        {
            get { return dictionary.Count; }
        }

        public bool IsReadOnly
        {
            get { return dictionary.IsReadOnly; }
        }

        public bool ContainsKey(K key)
        {
            return dictionary.ContainsKey(key);
        }

        public void Add(K key, V value)
        {
            dictionary.Add(key, value);
        }

        public bool Remove(K key)
        {
            return dictionary.Remove(key);
        }

        public bool TryGetValue(K key, out V value)
        {
            if (!dictionary.TryGetValue(key, out value))
                value = valueFactory(key);

            return true;
        }

        public V this[K key]
        {
            get
            {
                try
                {
                    return dictionary[key];
                }
                catch (KeyNotFoundException)
                {
                    return valueFactory(key);
                }
            }

            set { dictionary[key] = value; }
        }

        public ICollection<K> Keys
        {
            get { return dictionary.Keys; }
        }

        public ICollection<V> Values
        {
            get
            {
				return dictionary.Values;
            }
        }
    }
}
